#include <stdio.h>
#include <assert.h>

#include "aba_memory.h"
#include "instruction.h"
#include "core.h"

static void clock(Core *core);
void init_core(Core* core, char* memory, size_t code_start)
{
	assert(code_start < MAXMEM);

	core->memory = memory;
	core->code = memory + code_start;
	core->clock = clock;
	core->reg_pc = 0;
	core->halted = 0;	/* TODO replace with false */
}

inline int halted(Core* core)
{
	return core->halted;
}

/**
 * functions private to the local file are defined below... 
 */

static void halt(Core* core)
{
	core->halted = 1;	/* TODO replace with true */
}

/* TODO need to optimize the performance, VERY IMPORTANT! */
static void clock(Core *core)
{
	assert(core && core->code && core->memory);

	if (halted(core))
		return;

	unsigned int pc = core->reg_pc;
	char* code = core->code;
	char* memory = core->memory;
	unsigned int *regfile = core->regfile;
	Inst* pInst = &code[pc];
	Inst inst = *pInst;
	short op, rs, rt, rd, sa, funct6;

	core->reg_pc += sizeof(Inst)/sizeof(*code); /* increment PC by 4 */
	if (inst == 0)
		halt(core);

	op = inst_op(inst);

	switch (op) {
		/* R-Type */
	case 0:
		rs = inst_rs(inst);
		rt = inst_rt(inst);
		rd = inst_rd(inst);
		sa = inst_sa(inst);
		funct6 = inst_funct6(inst);

		switch (funct6) {
		case 0x20:	/* add */
			regfile[rd] = regfile[rs] + regfile[rt];
			break;
		case 0x22:	/* sub */
			regfile[rd] = regfile[rs] - regfile[rt];
			break;
		case 0x0:	/* sll, shift left logical */
			regfile[rd] = regfile[rt] << sa;
			break;
		case 0x2:	/* srl, shift right logical */
			regfile[rd] = regfile[rt] >> sa;
			break;
		}
		break;		/* R-Type end */

		/* I-Type */
	case 0x08:		/* addi */		
		break;
	case 0x04:		/* beq */
		break;

		/* J-Type */
	case 0x02:		/* j */
		break;
	case 0x03:		/* jal */
		break;
	}

	printf("%8x->%8x: %8x %8x %8x %8x %8x %8x\n", 
	       pc, inst,
	       inst_op(inst),
	       inst_rs(inst), 
	       inst_rt(inst), 
	       inst_rd(inst), 
	       inst_sa(inst),
	       inst_funct6(inst));
}
